package com.mgq.juc.reentrantLock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author MaGuangQi
 * 读写锁
 * 当读操作远远多于写操作时,这时就可以使用ReentrantReadWriteLock, 读读并发,读写,写写都是互斥的
 * 读写模式互斥(读锁释放后,才能写)
 * [t1] com.mgq.juc.reentrantLock.DataContainer - 拿到读锁！
 * [t1] com.mgq.juc.reentrantLock.DataContainer - 读取操作 ...
 * [t1] com.mgq.juc.reentrantLock.DataContainer - 释放读锁！
 * [t2] com.mgq.juc.reentrantLock.DataContainer - 拿到写锁
 * [t2] com.mgq.juc.reentrantLock.DataContainer - 写操作 ...
 * [t2] com.mgq.juc.reentrantLock.DataContainer - 释放写锁！
 *  读读模式(并发执行)
 * [t1] com.mgq.juc.reentrantLock.DataContainer - 拿到读锁！
 * [t1] com.mgq.juc.reentrantLock.DataContainer - 读取操作 ...
 * [t2] com.mgq.juc.reentrantLock.DataContainer - 拿到读锁！
 * [t2] com.mgq.juc.reentrantLock.DataContainer - 读取操作 ...
 * [t1] com.mgq.juc.reentrantLock.DataContainer - 释放读锁！
 * [t2] com.mgq.juc.reentrantLock.DataContainer - 释放读锁！
 * @date 2021-12-23 09:05
 **/
public class TestReentrantReadWriteLock {
    public static void main(String[] args) throws InterruptedException {
        DataContainer dataContainer = new DataContainer();
        new Thread(dataContainer::write,"t1").start();
        //Thread.sleep(1000);
        new Thread(dataContainer::write,"t2").start();
    }
}

/**
 * 数据容器,用读锁保护数据read()方法,写锁保护write()
 */
@Slf4j
class DataContainer {
    //保护的对象
    private Object object=new Object();
    ReentrantReadWriteLock rrw = new ReentrantReadWriteLock();
    ReentrantReadWriteLock.WriteLock writeLock = rrw.writeLock();
    ReentrantReadWriteLock.ReadLock readLock = rrw.readLock();

    /**
     * 读锁保护read()
     * @return
     */
    public Object read() {
        readLock.lock();
        try {
            log.info("拿到读锁！");
            log.info("读取操作 ...");
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();
            log.info("释放读锁！");
        }
        return object;
    }

    /**
     * 写锁保护write
     */
    public void write() {
        writeLock.lock();
        try {
            log.info("拿到写锁");
            log.info("写操作 ... ");
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock();
            log.info("释放写锁！");
        }
    }

}
